package cz.muni.fi.pb138.xml.wrda.controller;

import cz.muni.fi.pb138.xml.wrda.core.WAR;
import cz.muni.fi.pb138.xml.wrda.servise.WARService;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;

/**
 * Controller for WAR repository part of web application
 * @author Michal Krajcovic <422783@mail.muni.cz>
 * @version 5/8/14
 */
@Controller
@RequestMapping("/war")
public class WARController {

    @Autowired
    private WARService warService;

    /**
     * Returns ModelAndView with upload form
     * @return
     */
    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public ModelAndView addNew() {
        return new ModelAndView("war_add");
    }

    /**
     * Done after clicking upload button from upload form
     * Creates new war file in repository and saves it's metadata to database
     * @param request
     * @param fileUpload WAR archive to upload
     * @return
     */
    @RequestMapping(value = "/add/", method = RequestMethod.POST)
    public ModelAndView addNew(HttpServletRequest request, @RequestParam CommonsMultipartFile[] fileUpload) {
        if (fileUpload != null && fileUpload.length > 0) {
            for (CommonsMultipartFile fileToSave : fileUpload) {
                if (!fileToSave.getOriginalFilename().equals("")) {
                    if (StringUtils.endsWith(fileToSave.getOriginalFilename(), ".war")) {
                        try {
                            final Long timeStamp = System.currentTimeMillis();
                            String fileName = fileToSave.getOriginalFilename();
                            File warFile = warService.createFile(fileName, timeStamp);

                            OutputStream os = new FileOutputStream(warFile);
                            InputStream is = fileToSave.getInputStream();

                            IOUtils.copy(is, os);

                            is.close();
                            os.close();

                            warService.saveDbEntry(warFile, timeStamp);
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                    }
                }
            }
        }

        return new ModelAndView("redirect:/war/browse");
    }

    /**
     * Returns ModelAndView with list of all names of war archives saved in repository
     * @return
     */
    @RequestMapping(value = "/browse", method = RequestMethod.GET)
    public ModelAndView browse() {
        return new ModelAndView("war_browse", "wars", warService.getFileNames());
    }

    /**
     * Returns ModelAndView with list of war archives based on search result
     * @param searchValue value searched for
     * @param searchOption
     * @return
     */
    @RequestMapping(value = "/browse", method = RequestMethod.POST)
    public ModelAndView searchAndBrowse(@RequestParam String searchValue,
                                        @RequestParam String searchOption) {
        List<WAR> wars = null;
        if (searchOption.equals("filter")) {
            wars = warService.getByFilter(searchValue);
        } else if (searchOption.equals("listener")) {
            wars = warService.getByListener(searchValue);
        } else {
            wars = warService.getByFileName(searchValue);
        }

        return new ModelAndView("war_browse_result", "wars", wars);
    }

    /**
     * Removes given WAR archive from repository
     * @param fileName file name of WAR archive to delete
     * @param timeStamp time stamp of WAR archive to delete
     * @param response
     * @throws IOException
     */
    @RequestMapping(value = "/remove/{fileName}/{timeStamp}")
    public void remove(@PathVariable String fileName, @PathVariable Long timeStamp, HttpServletResponse response) throws IOException {
        WAR war = warService.getByFileNameAndTimeStamp(fileName, timeStamp);
        if (war != null) warService.delete(war);
        response.sendRedirect("/war/browse");
    }

    /**
     * Returns ModelAndView with list of all version of given WAR archive file name from repository
     * @param fileName
     * @param request
     * @return
     * @throws NoSuchRequestHandlingMethodException
     */
    @RequestMapping(value = "/browse/{fileName}")
    public ModelAndView browseVersions(@PathVariable String fileName, HttpServletRequest request) throws NoSuchRequestHandlingMethodException {
        List<WAR> wars = warService.getByFileName(fileName);
        if(wars.isEmpty()) throw new NoSuchRequestHandlingMethodException(request);
        return new ModelAndView("war_versions", "wars", wars);
    }

    /**
     * Returns ModelAndView with meta data and web.xml of single specific WAR archive from repository
     * @param fileName
     * @param timeStamp
     * @param request
     * @return
     * @throws NoSuchRequestHandlingMethodException
     */
    @RequestMapping(value = "/browse/{fileName}/{timeStamp}")
    public ModelAndView browseEntry(@PathVariable String fileName,
                                    @PathVariable Long timeStamp, HttpServletRequest request) throws NoSuchRequestHandlingMethodException {
        WAR war = warService.getByFileNameAndTimeStamp(fileName, timeStamp);
        if(war == null) throw new NoSuchRequestHandlingMethodException(request);
        return new ModelAndView("war_entry", "war", war);
    }

    /**
     * Returns single specific WAR archive file to download
     * @param fileName
     * @param timeStamp
     * @param response
     * @throws IOException
     */
    @RequestMapping(value = "/download/{fileName}/{timeStamp}", method = RequestMethod.GET, produces = "application/zip")
    @ResponseBody
    public void download(@PathVariable String fileName, @PathVariable Long timeStamp, HttpServletResponse response) throws IOException {
        WAR war = warService.getByFileNameAndTimeStamp(fileName, timeStamp);
        if (war != null) {
            File downloadFile = new File("repo/war/" + war.getFileName() + "/" + war.getTimeStamp() + ".war");
            InputStream is = new FileInputStream(downloadFile);
            response.setContentType("application/war");
            response.setHeader("Content-disposition", "attachment; filename="+ war.getFileName()+"-" + war.getTimeStamp() + ".war");
            IOUtils.copy(is, response.getOutputStream());
            response.flushBuffer();
        }
    }

}
